#pragma once

#include "../detail/box_alloc.hh"
#include <limits>
#include <cstddef>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <list>
#include <stack>

namespace kratos {
namespace service {

template <typename T> class Allocator {
public:
  typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef T*        pointer;
  typedef const T*  const_pointer;
  typedef T&        reference;
  typedef const T&  const_reference;
  typedef T         value_type;

  template <typename V> struct rebind {
    typedef Allocator<V> other;
  };
  pointer address(reference value) const {
    return &value;
  }
  const_pointer address(const_reference value) const {
    return &value;
  }
  Allocator() noexcept {
  }
  Allocator(const Allocator &) noexcept {
  }
  template <typename V> Allocator(const Allocator<V> &other) {
  }
  ~Allocator() noexcept {
  }
  size_type max_size() const noexcept {
#ifdef max
#undef max
#endif
    return std::numeric_limits<size_type>::max() / sizeof(T);
  }
  pointer allocate(size_type num) {
    return (pointer)(box_malloc(num * sizeof(T)));
  }
  void construct(pointer p, const T &value) {
    new ((void *)p) T(value);
  }
  void destroy(pointer p) {
    p->~T();
  }
  void deallocate(pointer p, size_type num) {
    box_free((void *)p);
  }
};

template <typename T, typename V>
bool operator==(const Allocator<T> &, const Allocator<V> &) noexcept {
  return true;
}

template <typename T, typename V>
bool operator!=(const Allocator<T> &, const Allocator<V> &) noexcept {
  return false;
}

using PoolString = std::basic_string<char, std::char_traits<char>, Allocator<char>>;

template <typename K, typename V>
using PoolUnorederedMap = std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, Allocator<std::pair<const K, V>>>;

template <typename K>
using PoolUnorderedSet = std::unordered_set<K, std::hash<K>, std::equal_to<K>, Allocator<K>>;

template <typename E>
using PoolList = std::list<E, Allocator<E>>;

template <typename E>
using PoolVector = std::vector<E, Allocator<E>>;

template <typename E>
using PoolStack= std::stack<E, PoolVector<E>>;

} // namespace service
} // namespace kratos
